#include "StdAfx.h"
#include "P2P.h"
#include "P2PProtocolImpl.h"

CP2PProtocolImpl::CP2PProtocolImpl( CP2P* p2p )
{
    m_p2p = p2p;
}

CP2PProtocolImpl::~CP2PProtocolImpl(void)
{
}

bool CP2PProtocolImpl::HandleClientPkg( char* net_data, int net_size )
{
    return HandleProtocol(net_data, net_size, m_recv_pkg_cache);
}

int CP2PProtocolImpl::BuildPkg( void* host, char*& net )
{
    net = m_send_pkg_cache;

    int& pkg_len = *(int*)m_send_pkg_cache;

    pkg_len = BuildProtocol(host, m_send_pkg_cache+sizeof(int), sizeof(m_send_pkg_cache)-sizeof(int));

    if (pkg_len < 0)
    {
        return -1;
    }

    pkg_len += sizeof(int);

    return pkg_len;
}

void CP2PProtocolImpl::OnRecv_LoginAck( LoginAck& rstProtocol )
{
    if (!m_p2p->get_current_host_session())
    {
        return;
    }

    if (rstProtocol.err_code)
    {
        m_p2p->get_host().DisConnect();
        return;
    }

    m_p2p->set_p2p_id(rstProtocol.p2p_id);

    if (!m_p2p->Open(m_p2p->get_net_manager()->GetLocalIP(m_p2p->get_host().get_session()), 
        m_p2p->get_net_manager()->GetLocalPort(m_p2p->get_host().get_session())))
    {
        m_p2p->get_host().DisConnect();
        return;
    }

    CNATTestSession* nat_test_session = m_p2p->get_p2p_session_manager().get_nat_test_session_pool().AllocObj();
    nat_test_session->set_p2p(m_p2p);

    if (!nat_test_session->Test(m_p2p->get_net_manager()->GetLocalIP(m_p2p->get_host().get_session()), 
        m_p2p->get_net_manager()->GetLocalPort(m_p2p->get_host().get_session()),
        m_p2p->get_net_manager()->GetPeerIP(m_p2p->get_host().get_session()),
        m_p2p->get_nat_test_port()))
    {
        m_p2p->get_host().DisConnect();
        return;
    }
}

void CP2PProtocolImpl::OnRecv_NATTestAck( NATTestAck& rstProtocol )
{
    if (!m_p2p->get_current_host_session())
    {
        return;
    }
    m_p2p->set_nat_type(rstProtocol.nat_type);
    m_p2p->get_p2p_session_call_back()->OnLogin(0, m_p2p->get_p2p_id());
}

void CP2PProtocolImpl::OnRecv_ConnectPeerAck( ConnectPeerAck& rstProtocol )
{
    if (!m_p2p->get_current_host_session())
    {
        return;
    }

    if (m_p2p->get_p2p_session_manager().FindP2PSession(rstProtocol.dst_p2p_id))
    {
        return;
    }

    if (m_p2p->get_p2p_session_manager().FindPeerInfo(rstProtocol.dst_p2p_id))
    {
        return;
    }

    PeerInfo* peer_info = m_p2p->get_p2p_session_manager().get_peer_info_pool().AllocObj();
    peer_info->nat_type = rstProtocol.dst_nat_type;
    peer_info->p2p_id = rstProtocol.dst_p2p_id;
    peer_info->public_ip = rstProtocol.dst_public_ip;
    peer_info->public_port = rstProtocol.dst_public_port;
    peer_info->private_ip = rstProtocol.dst_private_ip;
    peer_info->private_port = rstProtocol.dst_private_port;
    peer_info->stat = P2P_STAT_CONNECTING;

    m_p2p->get_p2p_session_manager().AddPeerInfo(*peer_info);

    CPunchSession* punch_session = m_p2p->get_p2p_session_manager().get_punch_session_pool().AllocObj();
    punch_session->set_p2p(m_p2p);
    punch_session->Punch(peer_info->public_ip, peer_info->public_port, 1, 1000);

    CP2PSession* p2p_session = m_p2p->get_p2p_session_manager().get_p2p_session_pool().AllocObj();
    p2p_session->Reset();
    p2p_session->set_p2p_id(peer_info->p2p_id);
    p2p_session->set_p2p(m_p2p);
    p2p_session->Start();

}

void CP2PProtocolImpl::OnRecv_PeerConnectReq( PeerConnectReq& rstProtocol )
{
    if (!m_p2p->get_current_host_session())
    {
        return;
    }

    if (m_p2p->get_p2p_session_manager().FindP2PSession(rstProtocol.peer_p2p_id))
    {
        return;
    }

    if (m_p2p->get_p2p_session_manager().FindPeerInfo(rstProtocol.peer_p2p_id))
    {
        return;
    }

    PeerInfo* peer_info = m_p2p->get_p2p_session_manager().get_peer_info_pool().AllocObj();
    peer_info->nat_type = rstProtocol.peer_nat_type;
    peer_info->p2p_id = rstProtocol.peer_p2p_id;
    peer_info->public_ip = rstProtocol.peer_public_ip;
    peer_info->public_port = rstProtocol.peer_public_port;
    peer_info->private_ip = rstProtocol.peer_private_ip;
    peer_info->private_port = rstProtocol.peer_private_port;
    peer_info->stat = P2P_STAT_CONNECTING;

    m_p2p->get_p2p_session_manager().AddPeerInfo(*peer_info);

    CPunchSession* punch_session = m_p2p->get_p2p_session_manager().get_punch_session_pool().AllocObj();

    punch_session->set_p2p(m_p2p);
    punch_session->Punch(peer_info->public_ip, peer_info->public_port, 100, 1000);
}

void CP2PProtocolImpl::OnRecv_P2PHandleReq( P2PHandleReq& rstProtocol )
{
    if (!m_p2p->get_current_p2p_session())//g_current_p2p_session)
    {
        return;
    }

    CP2PSession* my_p2p_session = m_p2p->get_p2p_session_manager().FindP2PSession(rstProtocol.my_p2p_id);
    if (my_p2p_session)
    {
        if (my_p2p_session != m_p2p->get_current_p2p_session())
        {
            m_p2p->get_current_p2p_session()->DisConnect();
        }

        return;
    }

    P2PHandleAck stAck;
    stAck.my_p2p_id = m_p2p->get_p2p_id();

    if (!m_p2p->get_current_p2p_session()->SendPkg(&stAck))
    {
        m_p2p->get_current_p2p_session()->DisConnect();
        return;
    }

    m_p2p->get_p2p_session_manager().AddP2PSession(*m_p2p->get_current_p2p_session());
    m_p2p->get_current_p2p_session()->set_stat(P2P_STAT_OK);

    m_p2p->get_p2p_session_call_back()->OnOpen(rstProtocol.my_p2p_id);
}

void CP2PProtocolImpl::OnRecv_P2PHandleAck( P2PHandleAck& rstProtocol )
{
    if (!m_p2p->get_current_p2p_session())
    {
        return;
    }

    CP2PSession* my_p2p_session = m_p2p->get_p2p_session_manager().FindP2PSession(rstProtocol.my_p2p_id);
    if (my_p2p_session)
    {
        if (my_p2p_session != m_p2p->get_current_p2p_session())
        {
            m_p2p->get_current_p2p_session()->DisConnect();
        }

        return;
    }

    m_p2p->get_p2p_session_manager().AddP2PSession(*m_p2p->get_current_p2p_session());
    m_p2p->get_current_p2p_session()->set_stat(P2P_STAT_OK);

    m_p2p->get_p2p_session_call_back()->OnOpen(rstProtocol.my_p2p_id);
}
